﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataMgr.File
{
    /// <summary>
    /// 统计工步层和循环层数据
    /// </summary>
    class DataStatistics
    {
        public FileRecordsRead RecordReader { get; set; }
        private List<StepStatisticsNode> m_steps = new List<StepStatisticsNode>();
        private List<CycleStatisticsNode> m_cycles = new List<CycleStatisticsNode>();
        public void SetStepStatis(List<STEP_STATIS> listSteps)
        {
            for (int i = 0; i < listSteps.Count; ++i)
            {
                StepStatisticsNode stStep = new StepStatisticsNode();
                stStep.dwStepIndex = listSteps[i].dwStepID;
                stStep.btStepType = listSteps[i].btStepType;
                stStep.nTimeSection = listSteps[i].dwTimeSection;
                stStep.dCap = listSteps[i].dCapEnd;
                stStep.dEng = listSteps[i].dEng;
                stStep.dVolStart = listSteps[i].dVolStart;
                stStep.dVolEnd = listSteps[i].dVolEnd;
                stStep.dTempStart = listSteps[i].dTmpStart;
                stStep.dTempEnd = listSteps[i].dTmpEnd;
                stStep.dwFirstRecordIndex = listSteps[i].dwFirstRecordIndex;
                stStep.dwLastRecordIndex = listSteps[i].dwLastRecordIndex;
                //读取首尾记录序号
                BdfRecord pRecord = RecordReader.GetCurRecord(stStep.dwFirstRecordIndex);

                stStep.dwFirstRecordSeq = pRecord.GetRecordID();
                pRecord = RecordReader.GetCurRecord(stStep.dwLastRecordIndex);

                stStep.dwLastRecordSeq = pRecord.GetRecordID();

                stStep.stepID = (UInt16)pRecord.GetStepNo();
                stStep.nOrgCycleID = (Int16)pRecord.GetCycleID();
                stStep.nRecordTotalNum = listSteps[i].nRecordsCount;
                m_steps.Add(stStep);
            }
        }

        public void CreateCyclesByCycleID()
        {
            UInt32 iStep = 0;
            int nOrgCycleID = -1;
            UInt32 dwCycleIndex = 0;

            m_cycles.Clear();
            CycleStatisticsNode cycle = new CycleStatisticsNode();
            cycle.vecSteps = new List<StepStatisticsNode>();
            foreach (StepStatisticsNode item in m_steps)
            {
                if (nOrgCycleID != item.nOrgCycleID)
                {
                    if (nOrgCycleID != -1)
                    {
                        m_cycles.Add(cycle);
                        cycle = new CycleStatisticsNode();
                        cycle.vecSteps = new List<StepStatisticsNode>();
                    }

                    cycle.dwCycleIndex = dwCycleIndex++;
                    cycle.dwStartStepIndex = iStep;
                }

                nOrgCycleID = item.nOrgCycleID;
                cycle.dwEndStepIndex = iStep++;
                cycle.vecSteps.Add(item);
            }

            m_cycles.Add(cycle);
            StatisticsCycle();
        }

        public void CreateCycleByStepCount(int nStepCount, int nStepBegin)
        {
            if (0 >= nStepCount || nStepBegin < 1)
                return;

            m_cycles.Clear();
            UInt32 iStep = 0;
            UInt32 dwCycleIndex = 0;
            CycleStatisticsNode cycle = new CycleStatisticsNode();
            foreach (StepStatisticsNode item in m_steps)
            {
                if (item.dwStepIndex + 1 == nStepBegin - 1 ||
                    ((item.dwStepIndex - nStepBegin + 2) % nStepCount == 0 && item.dwStepIndex + 1 > nStepBegin - 1))
                {
                    if (dwCycleIndex != 0)
                    {
                        m_cycles.Add(cycle);
                        cycle = new CycleStatisticsNode();
                        cycle.vecSteps = new List<StepStatisticsNode>();
                    }

                    cycle.dwCycleIndex = dwCycleIndex++;
                    cycle.dwStartStepIndex = iStep;
                }

                cycle.dwEndStepIndex = iStep++;
                cycle.vecSteps.Add(item);
            }

            m_cycles.Add(cycle);
            StatisticsCycle();
        }

        public void CreateCycleByChargeStep(bool bChgFirst = true)
        {
            m_cycles.Clear();
            UInt32 iStep = 0;
            UInt32 dwCycleIndex = 0;
            byte btLastStepType = 0;
            bool bHaveNewCycle = true;
            byte btOneCycle = 0;   //存放是否满足一个充放循环
            CycleStatisticsNode cycle = new CycleStatisticsNode();
            foreach (StepStatisticsNode item in m_steps)
            {
                if (btLastStepType != item.btStepType)
                {
                    int stepKind = DaFileElement.SwitchStepType(item.btStepType);
                    if (1 == stepKind)
                    {
                        if (btOneCycle == 2)   //满足一个充放循环
                            bHaveNewCycle = true;

                        btOneCycle = 1;
                    }

                    if ((bChgFirst && 0 == stepKind) || (!bChgFirst && 1 == stepKind))
                    {
                        if (btOneCycle == 1 || dwCycleIndex == 0)
                            btOneCycle = 2;
                    }

                    if (bHaveNewCycle)
                    {
                        if (dwCycleIndex != 0)
                        {
                            m_cycles.Add(cycle);
                            cycle = new CycleStatisticsNode();
                            cycle.vecSteps = new List<StepStatisticsNode>();
                        }

                        cycle.dwCycleIndex = dwCycleIndex++;
                        cycle.dwStartStepIndex = iStep;
                    }
                }

                cycle.dwEndStepIndex = iStep++;
                btLastStepType = item.btStepType;
                cycle.vecSteps.Add(item);
            }

            m_cycles.Add(cycle);
            StatisticsCycle();
        }
        void StatisticsCycle()
        {
            //foreach (CycleStatisticsNode item in m_cycles)
            for (int cycleIndex=0; cycleIndex < m_cycles.Count; cycleIndex++)
            {
                var itemC = m_cycles.Where(c => c.dwCycleIndex == cycleIndex).FirstOrDefault();
                itemC.dCrgCap = 0;
                itemC.dDcrgCap = 0;
                itemC.dDcrgEng = 0;
                itemC.dCrgEng = 0;

                for (Int32 iS = (int)itemC.dwStartStepIndex; iS <= itemC.dwEndStepIndex; iS++)
                {
                    StepStatisticsNode pStep = m_steps[iS];
                    if (1 == DaFileElement.SwitchStepType(m_steps[iS].btStepType))
                    {
                        itemC.dCrgCap += m_steps[iS].dCap;
                        itemC.dCrgEng += m_steps[iS].dEng;
                    }
                    else if (0 == DaFileElement.SwitchStepType(m_steps[iS].btStepType))
                    {
                        itemC.dDcrgCap += m_steps[iS].dCap;
                        itemC.dDcrgEng += m_steps[iS].dEng;
                    }
                }

                itemC.ullChargeTime = GetCycleChargeDischangeTime((int)itemC.dwCycleIndex, 1);
                itemC.ullDischargeTime = GetCycleChargeDischangeTime((int)itemC.dwCycleIndex, 0);
                itemC.dMedianVoltage = GetCycleMidVol((int)itemC.dwCycleIndex);
                itemC.bCalc = true;
            }
            //m_cycles.ForEach(itemC =>
            //{
            //    itemC.dCrgCap = 0;
            //    itemC.dDcrgCap = 0;
            //    itemC.dDcrgEng = 0;
            //    itemC.dCrgEng = 0;

            //    for (Int32 iS = (int)itemC.dwStartStepIndex; iS <= itemC.dwEndStepIndex; iS++)
            //    {
            //        StepStatisticsNode pStep = m_steps[iS];
            //        if (1 == DaFileElement.SwitchStepType(m_steps[iS].btStepType))
            //        {
            //            itemC.dCrgCap += m_steps[iS].dCap;
            //            itemC.dCrgEng += m_steps[iS].dEng;
            //        }
            //        else if (0 == DaFileElement.SwitchStepType(m_steps[iS].btStepType))
            //        {
            //            itemC.dDcrgCap += m_steps[iS].dCap;
            //            itemC.dDcrgEng += m_steps[iS].dEng;
            //        }
            //    }

            //    itemC.ullChargeTime = GetCycleChargeDischangeTime((int)itemC.dwCycleIndex,1);
            //    itemC.ullDischargeTime = GetCycleChargeDischangeTime((int)itemC.dwCycleIndex,0);
            //    itemC.bCalc = true;
            //});
        }

        public List<CycleStatisticsNode> GetCycles()
        {
            return m_cycles;
        }

        public StepStatisticsNode GetStepNode(int stepIndex)
        {
            //if (stepIndex < m_steps.Count)
                return m_steps[stepIndex];
        }

       public UInt64 GetCycleChargeDischangeTime(int dwCycleIndex, int chgFlag)
        {
            Int32 dwStartStep = (int)m_cycles[dwCycleIndex].dwStartStepIndex;
            Int32 dwEndStep = (int)m_cycles[dwCycleIndex].dwEndStepIndex;
            UInt64 nTime = 0;
            for (; dwStartStep <= dwEndStep; dwStartStep++)
            {
                if (chgFlag == DaFileElement.SwitchStepType(m_steps[dwStartStep].btStepType))
                {
                    nTime += m_steps[dwStartStep].nTimeSection;
                }
            }

            return nTime;
        }
        public double GetCycleMidVol(int dwCycleIndex)
        {
            Int32 dwFirstStep = (int)m_cycles[dwCycleIndex].dwStartStepIndex;
            Int32 dwLastStep = (int)m_cycles[dwCycleIndex].dwEndStepIndex;
            for (; dwFirstStep <= dwLastStep; dwFirstStep++)
            {
                if (0 == DaFileElement.SwitchStepType(m_steps[dwFirstStep].btStepType))
                {
                    return GetStepDcrgMidVol(dwFirstStep);
                }
            }

            return 0;
        }

 
        public double GetStepDcrgMidVol(int dwStepIndex)
        {
            if (m_steps[dwStepIndex].bDcrgMidVolCalc)
                return m_steps[dwStepIndex].dDcrgMidVol;    //如果计算过，就直接返回

            //计算
            if (0 != DaFileElement.SwitchStepType(m_steps[dwStepIndex].btStepType))
            {
                //非充电工步，就返回
                //改变list中某个元素值
                var st = m_steps.Where(c => c.dwStepIndex == dwStepIndex).FirstOrDefault();
                st.bDcrgMidVolCalc = true;
                st.dDcrgMidVol = 0.0;

                return 0.0;
            }

            UInt32 dwFirstPos = m_steps[dwStepIndex].dwFirstRecordIndex;
            UInt32 dwLastPos = m_steps[dwStepIndex].dwLastRecordIndex;
            UInt32 dwPreSeq = 0;
            UInt32 dwPos = 0;

            double ullCap = 0;
            BdfRecord pRecord = RecordReader.GetCurRecord(dwLastPos);

            if (pRecord != null )
            {
                ullCap = pRecord.GetCap()/2;
            }

            dwPreSeq = 0;
            dwPreSeq = 0;

            double ullFirstCap = 0;
            double ullSecondCap = 0;
            bool bFirst = true;
            bool bFound = false;
            double iFirstVol = 0;
            double iMidVol = 0;
            for (dwPos = dwFirstPos ; dwPos <= dwLastPos; dwPos++)
            {
                BdfRecord record = RecordReader.GetCurRecord(dwLastPos);
                if (record == null )
                {
                    continue;
                }

                if (bFirst)
                {
                    bFirst = false;
                }
                else
                {
                    ullSecondCap = record.GetCap();
                    //if( ullFirstCap <= ullCap && ullCap <= ullSecondCap )
                    if (ullSecondCap <= ullCap && ullCap <= ullFirstCap)//放电容量为负，ullSecondCap<ullFirstCap
                    {
                        double ullFirstX = ullCap - ullFirstCap;
                        double ullSecondX = ullSecondCap - ullCap;
                        if (ullFirstX < ullSecondX)
                        {
                            iMidVol = iFirstVol;
                        }
                        else
                        {
                            iMidVol = record.GetVol();
                        }
                        bFound = true;
                        break;
                    }
                }

                iFirstVol = record.GetVol();
                ullFirstCap = record.GetCap();
            }

            if (!bFound)
            {
                iMidVol = iFirstVol;
            }

            var model = m_steps.Where(c => c.dwStepIndex == dwStepIndex).FirstOrDefault();
            model.dDcrgMidVol = (iMidVol);
            model.bDcrgMidVolCalc = true;
            return model.dDcrgMidVol;
        }
    }



    struct StepStatisticsNode
    {
        public UInt32 dwStepIndex;    //工步序号 >= 0
        public Byte btStepType;     //工步类型
        public UInt16 stepID;            //原始工步序号
        public Int16 nOrgCycleID;    // 工步的第一条记录对应的原始cycleID, 指的是数据库中df数据的循环号
        public UInt64 nTimeSection;   //工步的持续时间 ms
        public double dCap;            //容量 /mAh
        public double dEng;            //能量 /mAh
        public double dVolStart;       //起始电压 /V
        public double dVolEnd;         //终止电压 /V
        public double dTempStart;      //起始温度 /℃
        public double dTempEnd;        //终止温度 /℃
        public double dCrgMidVol;      //充电中值电压 /V,如果工步类型为非充电，此处为0
        public double dDcrgMidVol;     //放电中值电压 /V,如果工步类型为非放电，此处为0
        public double dSuperCapa;      //超级电容 /F
        public double dCrgCap;     //充电容量 /mAh
        public double dDcrgCap;    //放电容量 /mAh
        public UInt32 nRecordTotalNum;  //有效记录总数
        public UInt32 dwFirstRecordSeq; //工步的第一条有效记录的序号
        public UInt32 dwLastRecordSeq;  //工步的最后一条有效记录的序号
        public UInt32 dwFirstRecordIndex;   //在所有有效记录中的起始位置
        public UInt32 dwLastRecordIndex;    //在所有有效记录中的结束位置
                                            //标识充电中值电压是否已经计算过（注：中值电压的计算需要消耗所有时间，因此加以标识）
        public bool bCrgMidVolCalc;
        //标识放电中值电压是否已经计算过（注：中值电压的计算需要消耗所有时间，因此加以标识）
        public bool bDcrgMidVolCalc;
        public bool bSuperCapaCalc;   //标识超级电容是否已经计算过
    }

    class CycleStatisticsNode   //如果用struct，在List<中无法修改值,2020-2-5
    {
        public UInt32 dwCycleIndex;     //循环序号>=0
        public double dCrgCap;     //充电容量 /mAh
        public double dDcrgCap;    //放电容量 /mAh
        public double dCrgEng;     //充电能量 /mWh
        public double dDcrgEng;    //放电能量 /mWh
        public UInt64 ullChargeTime;     //充电时间
        public UInt64 ullDischargeTime;  //放电时间
        public bool bCalc; //循环统计节点数据是否已计算
        public double dCC_Cap;     //恒流充入的容量/ mAh
        public bool bCalc_CC_Cap;  //恒流充入容量是否已计算
        public double dPlatformCap;      // 平台容量
        public double dPlatformTotalCap; // 平台所在工步的总容量
        public UInt64 nPlatformTime;     // 平台时间
        public bool bCalc_Platform;      // 是否计算了平台
        public UInt32 dwStartStepIndex;
        public UInt32 dwEndStepIndex;
        public double dMedianVoltage;                //中值电压
        public List<StepStatisticsNode> vecSteps;  //属于该循环的工步节点的指针集合
    }
}
